﻿using System;
using System.Diagnostics;
using System.IO;
using Microsoft.Data.Schema.SchemaModel;
using Microsoft.Data.Schema.Sql.SchemaModel;
using Microsoft.Data.Schema.StaticCodeAnalysis;
using Microsoft.Data.Schema;
using System.Collections;
using System.Collections.Generic;

using System.Globalization;
using Microsoft.Data.Schema.Extensibility;
using Microsoft.Data.Schema.ScriptDom.Sql;
using Microsoft.Data.Schema.Sql;
using System.Linq;

namespace Neznayka
{
    public static class SqlComparisonUtils
    {
        public static bool Contains( SQLObjectFragment fragment1, SQLObjectFragment fragment2)
        {
            return 
                ( ( fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                  ( fragment1.LastTokenIndex  >= fragment2.LastTokenIndex)
                );
        }
        public static bool StrictlyContains(SQLObjectFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex < fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex > fragment2.LastTokenIndex)
                );
        }
        public static bool SemiContains(SQLObjectFragment fragment1, SQLObjectFragment fragment2)
        {
            return (
                     ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                      (fragment1.LastTokenIndex > fragment2.LastTokenIndex)
                     )
                   ||
                     ((fragment1.FirstTokenIndex < fragment2.FirstTokenIndex) &&
                      (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                     )
                   );
        }
        public static bool Equals(SQLObjectFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex == fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex == fragment2.LastTokenIndex)
                );
        }
        public static bool StartsWith(SQLObjectFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex == fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                );
        }
        public static bool EndsWith(SQLObjectFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex == fragment2.LastTokenIndex)
                );
        }
        public static bool Intersects(SQLObjectFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                ( ( (fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                    (fragment1.LastTokenIndex  >= fragment2.FirstTokenIndex)
                  )
                  ||
                  ( (fragment1.FirstTokenIndex <= fragment2.LastTokenIndex) &&
                    (fragment1.LastTokenIndex  >= fragment2.LastTokenIndex)
                  )
                );
        }


/// <summary>
/// /////////////////////
/// </summary>
/// <param name="fragment1"></param>
/// <param name="fragment2"></param>
/// <returns></returns>


        public static bool Contains(TSqlFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                );
        }
        public static bool StrictlyContains(TSqlFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex < fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex > fragment2.LastTokenIndex)
                );
        }
        public static bool SemiContains(TSqlFragment fragment1, SQLObjectFragment fragment2)
        {
            return (
                     ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                      (fragment1.LastTokenIndex > fragment2.LastTokenIndex)
                     )
                   ||
                     ((fragment1.FirstTokenIndex < fragment2.FirstTokenIndex) &&
                      (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                     )
                   );
        }
        public static bool Equals(TSqlFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex == fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex == fragment2.LastTokenIndex)
                );
        }
        public static bool StartsWith(TSqlFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex == fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                );
        }
        public static bool EndsWith(TSqlFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex == fragment2.LastTokenIndex)
                );
        }
        public static bool Intersects(TSqlFragment fragment1, SQLObjectFragment fragment2)
        {
            return
                (((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                    (fragment1.LastTokenIndex >= fragment2.FirstTokenIndex)
                  )
                  ||
                  ((fragment1.FirstTokenIndex <= fragment2.LastTokenIndex) &&
                    (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                  )
                );
        }

/// <summary>
/// /////////////////////
/// </summary>
/// <param name="fragment1"></param>
/// <param name="fragment2"></param>
/// <returns></returns>


        public static bool Contains(SQLObjectFragment fragment1, TSqlFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                );
        }
        public static bool StrictlyContains(SQLObjectFragment fragment1, TSqlFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex < fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex > fragment2.LastTokenIndex)
                );
        }
        public static bool SemiContains(SQLObjectFragment fragment1, TSqlFragment fragment2)
        {
            return (
                     ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                      (fragment1.LastTokenIndex > fragment2.LastTokenIndex)
                     )
                   ||
                     ((fragment1.FirstTokenIndex < fragment2.FirstTokenIndex) &&
                      (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                     )
                   );
        }
        public static bool Equals(SQLObjectFragment fragment1, TSqlFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex == fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex == fragment2.LastTokenIndex)
                );
        }
        public static bool StartsWith(SQLObjectFragment fragment1, TSqlFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex == fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                );
        }
        public static bool EndsWith(SQLObjectFragment fragment1, TSqlFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex == fragment2.LastTokenIndex)
                );
        }
        public static bool Intersects(SQLObjectFragment fragment1, TSqlFragment fragment2)
        {
            return
                (((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                    (fragment1.LastTokenIndex >= fragment2.FirstTokenIndex)
                  )
                  ||
                  ((fragment1.FirstTokenIndex <= fragment2.LastTokenIndex) &&
                    (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                  )
                );
        }


/// <summary>
/// /////////////////////
/// </summary>
/// <param name="fragment1"></param>
/// <param name="fragment2"></param>
/// <returns></returns>

        public static bool Contains(TSqlFragment fragment1, TSqlFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                );
        }
        public static bool StrictlyContains(TSqlFragment fragment1, TSqlFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex < fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex > fragment2.LastTokenIndex)
                );
        }
        public static bool SemiContains(TSqlFragment fragment1, TSqlFragment fragment2)
        {
            return (
                     ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                      (fragment1.LastTokenIndex > fragment2.LastTokenIndex)
                     )
                   ||
                     ((fragment1.FirstTokenIndex < fragment2.FirstTokenIndex) &&
                      (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                     )
                   );
        }
        public static bool Equals(TSqlFragment fragment1, TSqlFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex == fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex == fragment2.LastTokenIndex)
                );
        }
        public static bool StartsWith(TSqlFragment fragment1, TSqlFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex == fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                );
        }
        public static bool EndsWith(TSqlFragment fragment1, TSqlFragment fragment2)
        {
            return
                ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                  (fragment1.LastTokenIndex == fragment2.LastTokenIndex)
                );
        }
        public static bool Intersects(TSqlFragment fragment1, TSqlFragment fragment2)
        {
            return
                (((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
                    (fragment1.LastTokenIndex >= fragment2.FirstTokenIndex)
                  )
                  ||
                  ((fragment1.FirstTokenIndex <= fragment2.LastTokenIndex) &&
                    (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
                  )
                );
        }



//////////////

        //// really obscure code - to compare model elements with sqlfragment elements
        //// ie is a name in a piece of sql 

        //public static bool Contains(ModelCollationComparer cmp, string defaultSchema, TSqlFragment fragment1, ModelIdentifier fragment2)
        //{
        //    //match last element of name
        //    //work backwards, matching schema as supplied.
        //    int lastElement = fragment2.Parts.Count-1;

        //    List<String> sql = new List<string>() ;
                
        //    for ( int i = fragment1.FirstTokenIndex; i <= fragment1.LastTokenIndex;i++) {
        //        sql.Add(fragment1.ScriptTokenStream[i].Text);
        //    }
        //    List<int> matchpos = new List<string>();



        //    return
        //        ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
        //          (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
        //        );
        //}
        //public static bool StrictlyContains(ModelCollationComparer cmp, string defaultSchema, TSqlFragment fragment1, ModelIdentifier fragment2)
        //{
        //    return
        //        ((fragment1.FirstTokenIndex < fragment2.FirstTokenIndex) &&
        //          (fragment1.LastTokenIndex > fragment2.LastTokenIndex)
        //        );
        //}
        //public static bool SemiContains(ModelCollationComparer cmp, string defaultSchema, TSqlFragment fragment1, ModelIdentifier fragment2)
        //{
        //    return (
        //             ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
        //              (fragment1.LastTokenIndex > fragment2.LastTokenIndex)
        //             )
        //           ||
        //             ((fragment1.FirstTokenIndex < fragment2.FirstTokenIndex) &&
        //              (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
        //             )
        //           );
        //}
        //public static bool Equals(ModelCollationComparer cmp, string defaultSchema, TSqlFragment fragment1, ModelIdentifier fragment2)
        //{
        //    return
        //        ((fragment1.FirstTokenIndex == fragment2.FirstTokenIndex) &&
        //          (fragment1.LastTokenIndex == fragment2.LastTokenIndex)
        //        );
        //}
        //public static bool StartsWith(ModelCollationComparer cmp, string defaultSchema, TSqlFragment fragment1, ModelIdentifier fragment2)
        //{
        //    return
        //        ((fragment1.FirstTokenIndex == fragment2.FirstTokenIndex) &&
        //          (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
        //        );
        //}
        //public static bool EndsWith(ModelCollationComparer cmp, string defaultSchema, TSqlFragment fragment1, ModelIdentifier fragment2)
        //{
        //    return
        //        ((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
        //          (fragment1.LastTokenIndex == fragment2.LastTokenIndex)
        //        );
        //}
        //public static bool Intersects(ModelCollationComparer cmp, string defaultSchema, TSqlFragment fragment1, ModelIdentifier fragment2)
        //{
        //    return
        //        (((fragment1.FirstTokenIndex <= fragment2.FirstTokenIndex) &&
        //            (fragment1.LastTokenIndex >= fragment2.FirstTokenIndex)
        //          )
        //          ||
        //          ((fragment1.FirstTokenIndex <= fragment2.LastTokenIndex) &&
        //            (fragment1.LastTokenIndex >= fragment2.LastTokenIndex)
        //          )
        //        );
        //}
    }
//////////////

    // Custom comparer for the Subquery class
    //class SqlSubqueryComparer : IEqualityComparer<Subquery>
    //{
    //    // sql fragments are equal if their token ranges are equal.
    //    public bool Equals(Subquery x, Subquery y)
    //    {
    //        //Check whether the compared objects reference the same data.
    //        if (Object.ReferenceEquals(x, y)) return true;
    //        //Check whether any of the compared objects is null.
    //        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
    //            return false;
    //        //Check whether the sql token ranges are equal.
    //        return (SqlComparisonUtils.Equals(x,y));
    //    }

    //    // If Equals() returns true for a pair of objects 
    //    // then GetHashCode() must return the same value for these objects.

    //    public int GetHashCode(Subquery sql)
    //    {
    //        //Check whether the object is null
    //        if (Object.ReferenceEquals(sql, null)) return 0;
    //        //Calculate the hash code for the product.
    //        return sql.FirstTokenIndex;
    //    }

    //}

    class SqlLiteralComparer : IEqualityComparer<Literal>
    {
        // sql fragments are equal if their token ranges are equal.
        public bool Equals(Literal x, Literal y)
        {
            //Check whether the compared objects reference the same data.
            if (Object.ReferenceEquals(x, y)) return true;
            //Check whether any of the compared objects is null.
            if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
                return false;
            //Check whether the sql token ranges are equal.
            return (SqlComparisonUtils.Equals(x, y));
        }

        // If Equals() returns true for a pair of objects 
        // then GetHashCode() must return the same value for these objects.

        public int GetHashCode(Literal sql)
        {
            //Check whether the object is null
            if (Object.ReferenceEquals(sql, null)) return 0;
            //Calculate the hash code for the product.
            return sql.FirstTokenIndex;
        }

    }

    //static class TSQLFragmentOps
    //{
    //    public static void Push<T>(this List<T> TheList, T Value)
    //    {
    //        TheList.Add(Value);
    //    }
    //}


}